package org.activiti.explorer.servlet.dispatcher;

import java.util.EnumSet;

import javax.servlet.DispatcherType;
import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

import org.activiti.explorer.conf.ApplicationConfiguration;
import org.activiti.explorer.servlet.modeler.ModelerServletConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.filter.DelegatingFilterProxy;
import org.springframework.web.servlet.DispatcherServlet;

/**
 * Configuration of web application with Servlet 3.0 APIs.
 */
@WebListener
public class WebConfigurer implements ServletContextListener {

    private final Logger log = LoggerFactory.getLogger(WebConfigurer.class);

    //public AnnotationConfigWebApplicationContext context;
    //public AnnotationConfigEmbeddedWebApplicationContext embeddedContext;
    public WebApplicationContext context;
    //@Autowired
    //@Qualifier("ModelerServlet")
    //public DispatcherServlet dispatcherServlet;

    public void setContext(WebApplicationContext context) {
        this.context = context;
    }

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        ServletContext servletContext = sce.getServletContext();

        log.debug("Configuring Spring root application context");

        WebApplicationContext webApplicationContext = 
                WebApplicationContextUtils
                .getRequiredWebApplicationContext(servletContext);

        //AnnotationConfigWebApplicationContext rootContext = null;

        if (context == null) {
            if(webApplicationContext == null) {
                AnnotationConfigWebApplicationContext rootContext;
                rootContext = new AnnotationConfigWebApplicationContext();
                rootContext.register(ApplicationConfiguration.class);
                rootContext.refresh();
                rootContext.close();
                context = rootContext;
            } else {
                context = webApplicationContext;
            }
        } 

        servletContext.setAttribute(
                WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,
                context);

        EnumSet<DispatcherType> disps = 
                EnumSet.of(DispatcherType.REQUEST,DispatcherType.FORWARD, DispatcherType.ASYNC);

        //initSpring(servletContext, context);
        // initSpringSecurity(servletContext, disps);

        log.debug("Web application fully configured");
    }

    /**
     * Initializes Spring and Spring MVC.
     */
    //private ServletRegistration.Dynamic initSpring(
    private ServletRegistrationBean initSpring(
            ServletContext servletContext,
            WebApplicationContext webApplicationContext) {
            //AnnotationConfigWebApplicationContext rootContext) {
        log.debug("Configuring Spring Web application context");
        AnnotationConfigEmbeddedWebApplicationContext dispatcherServletConfiguration = 
                new AnnotationConfigEmbeddedWebApplicationContext();
//        AnnotationConfigWebApplicationContext dispatcherServletConfiguration = 
//                new AnnotationConfigWebApplicationContext();
        dispatcherServletConfiguration.setParent(webApplicationContext);
        dispatcherServletConfiguration.register(ModelerServletConfiguration.class);

        log.debug("Registering Spring MVC Servlet");
        ServletRegistrationBean dispatcherServlet = new ServletRegistrationBean();
        dispatcherServlet.setServlet(new DispatcherServlet(dispatcherServletConfiguration));
        //dispatcherServlet.setServlet(this.dispatcherServlet);
        dispatcherServlet.addUrlMappings("/service/*");//"/*"
        dispatcherServlet.setLoadOnStartup(1);
        dispatcherServlet.setAsyncSupported(true);

//        log.debug("Registering Spring MVC Servlet");
//        ServletRegistration.Dynamic dispatcherServlet = 
//                servletContext.addServlet("dispatcher", 
//                        new DispatcherServlet(dispatcherServletConfiguration));
//        dispatcherServlet.addMapping("/service/*");
//        // dispatcherServlet.addMapping("/*");
//        dispatcherServlet.setLoadOnStartup(1);
//        dispatcherServlet.setAsyncSupported(true);

        return dispatcherServlet;
    }

    /**
     * Initializes Spring Security.
     */
    private void initSpringSecurity(ServletContext servletContext,
            EnumSet<DispatcherType> disps) {
        log.debug("Registering Spring Security Filter");
        FilterRegistration.Dynamic springSecurityFilter = 
                servletContext.addFilter("springSecurityFilterChain",
                        new DelegatingFilterProxy());

        springSecurityFilter.addMappingForUrlPatterns(disps, false, "/*");
        springSecurityFilter.setAsyncSupported(true);
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        log.info("Destroying Web application");
        WebApplicationContext ac = 
                WebApplicationContextUtils.getRequiredWebApplicationContext(sce.getServletContext());
        if(ac instanceof AnnotationConfigEmbeddedWebApplicationContext){
            AnnotationConfigEmbeddedWebApplicationContext gwac = 
                    (AnnotationConfigEmbeddedWebApplicationContext) ac;
            gwac.close();
        } else if (ac instanceof AnnotationConfigWebApplicationContext) {
             AnnotationConfigWebApplicationContext gwac =
             (AnnotationConfigWebApplicationContext) ac;
             gwac.close();
        }
        log.debug("Web application destroyed");
    }
}
